{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 从 Matlab 到 Numpy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##Numpy  和 Matlab 比较"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**`Numpy`** 和 **`Matlab`** 有很多相似的地方，但 **`Numpy`** 并非 **`Matlab`** 的克隆，它们之间存在很多差异，例如：\n",
    "\n",
    "`MATLAB®`|`Numpy`\n",
    "---|---\n",
    "基本类型为双精度浮点数组，以二维矩阵为主 | 基本类型为 `ndarray`，有特殊的 `matrix` 类\n",
    "1-based 索引 | 0-based 索引\n",
    "脚本主要用于线性代数计算 | 可以使用其他的 **Python** 特性 \n",
    "采用值传递的方式进行计算<br>切片返回复制 | 采用引用传递的方式进行计算<br>切片返回引用\n",
    "文件名必须和函数名相同 | 函数可以在任何地方任何文件中定义\n",
    "收费 | 免费\n",
    "2D，3D图像支持 | 依赖第三方库如 `matplotlib` 等\n",
    "完全的编译环境 | 依赖于 **Python** 提供的编译环境"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## array 还是 matrix？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Numpy` 中不仅提供了 `array` 这个基本类型，还提供了支持矩阵操作的类 `matrix`，但是一般推荐使用 `array`：\n",
    "\n",
    "- 很多 `numpy` 函数返回的是 `array`，不是 `matrix`\n",
    "- 在 `array` 中，逐元素操作和矩阵操作有着明显的不同\n",
    "- 向量可以不被视为矩阵\n",
    "\n",
    "具体说来：\n",
    "\n",
    "- `*， dot(), multiply()`\n",
    "    - `array`：`*` -逐元素乘法，`dot()` -矩阵乘法\n",
    "    - `matrix`：`*` -矩阵乘法，`multiply()` -逐元素乘法\n",
    "- 处理向量 \n",
    "    - `array`：形状为 `1xN, Nx1, N` 的向量的意义是不同的，类似于 `A[:,1]` 的操作返回的是一维数组，形状为 `N`，一维数组的转置仍是自己本身\n",
    "    - `matrix`：形状为 `1xN, Nx1`，`A[:,1]` 返回的是二维 `Nx1` 矩阵\n",
    "- 高维数组\n",
    "    - `array`：支持大于2的维度\n",
    "    - `matrix`：维度只能为2\n",
    "- 属性\n",
    "    - `array`：`.T` 表示转置\n",
    "    - `matrix`：`.H` 表示复共轭转置，`.I` 表示逆，`.A` 表示转化为 `array` 类型\n",
    "- 构造函数\n",
    "    - `array`：`array` 函数接受一个（嵌套）序列作为参数——`array([[1,2,3],[4,5,6]])`\n",
    "    - `matrix`：`matrix` 函数额外支持字符串参数——`matrix(\"[1 2 3; 4 5 6]\")`\n",
    "\n",
    "其优缺点各自如下：\n",
    "\n",
    "- **`array`**\n",
    "    - `[GOOD]` 一维数组既可以看成列向量，也可以看成行向量。`v` 在 `dot(A,v)` 被看成列向量，在 `dot(v,A)` 中被看成行向量，这样省去了转置的麻烦\n",
    "    - `[BAD!]` 矩阵乘法需要使用 `dot()` 函数，如： `dot(dot(A,B),C)` vs `A*B*C`\n",
    "    - `[GOOD]` 逐元素乘法很简单： `A*B`\n",
    "    - `[GOOD]` 作为基本类型，是很多基于 `numpy` 的第三方库函数的返回类型\n",
    "    - `[GOOD]` 所有的操作 `*,/,+,**,...` 都是逐元素的\n",
    "    - `[GOOD]` 可以处理任意维度的数据\n",
    "    - `[GOOD]` 张量运算\n",
    "\n",
    "- **`matrix`**\n",
    "    - `[GOOD]` 类似与 **`MATLAB`** 的操作\n",
    "    - `[BAD!]` 最高维度为2\n",
    "    - `[BAD!]` 最低维度也为2\n",
    "    - `[BAD!]` 很多函数返回的是 `array`，即使传入的参数是 `matrix`\n",
    "    - `[GOOD]` `A*B` 是矩阵乘法\n",
    "    - `[BAD!]` 逐元素乘法需要调用 `multiply` 函数\n",
    "    - `[BAD!]` `/` 是逐元素操作\n",
    "\n",
    "当然在实际使用中，二者的使用取决于具体情况。\n",
    "\n",
    "二者可以互相转化：\n",
    "\n",
    "- `asarray` ：返回数组\n",
    "- `asmatrix`（或者`mat`） ：返回矩阵\n",
    "- `asanyarray` ：返回数组或者数组的子类，注意到矩阵是数组的一个子类，所以输入是矩阵的时候返回的也是矩阵"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 类 Matlab 函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有很多类似的函数：\n",
    "\n",
    "- `ones, zeros, empty, eye, rand, repmat`\n",
    "\n",
    "通常这些函数的返回值是 `array`，不过 `numpy` 提供了一个 `matlib` 的子模块，子模块中的这些函数返回值为 `matrix`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy\n",
    "import numpy.matlib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(7L,)\n",
      "<type 'numpy.ndarray'>\n"
     ]
    }
   ],
   "source": [
    "a = numpy.ones(7)\n",
    "\n",
    "print a.shape\n",
    "print type(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1L, 7L)\n",
      "<class 'numpy.matrixlib.defmatrix.matrix'>\n"
     ]
    }
   ],
   "source": [
    "a = numpy.matlib.ones(7)\n",
    "\n",
    "print a.shape\n",
    "print type(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`mat` 函数将一个数组转化为矩阵："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.matrixlib.defmatrix.matrix'>\n"
     ]
    }
   ],
   "source": [
    "a = numpy.array([1,2,3])\n",
    "\n",
    "b = numpy.mat(a)\n",
    "\n",
    "print type(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有些函数被放到子模块中了，例如调用 `rand()` 函数需要使用 `numpy.random.rand()` （或者从 `matlib` 模块中生成矩阵）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0.66007267  0.34794294  0.5040946   0.65044648  0.74763248  0.42486999\n",
      "  0.90922612  0.69071747  0.33541076  0.08570178]\n"
     ]
    }
   ],
   "source": [
    "a = numpy.random.rand(10)\n",
    "print a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 等效操作"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "假定我们已经这样导入了 `Numpy`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from numpy import *\n",
    "import scipy.linalg"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以下 `linalg` 表示的是 `numpy.linalg`，与 `scipy.linalg` 不同。\n",
    "\n",
    "注意：**`MATLAB`** 与 **`Numpy`** 下标之间有这样几处不同：\n",
    "- `1-base` vs `0-base`\n",
    "- `()` vs `[]`\n",
    "- `MATLAB`：`beg(:step):end`，包含结束值 `end`\n",
    "- `Numpy`：`beg:end(:step)`，不包含结束值 `end`\n",
    "\n",
    "MATLAB|Numpy|注释\n",
    "---|---|---\n",
    "`help func` | `info(func)`， `help(func)`， `func?`(IPython)| 查看函数帮助\n",
    "`which func` |  | 查看函数在什么地方定义\n",
    "`type func` | `source(func)`， `func?？`(IPython)| 查看函数源代码\n",
    "`a && b` | `a and b` | 逻辑 `AND`\n",
    "`1*i, 1*j, 1i, 1j` | `1j` | 复数\n",
    "`eps` | `spacing(1)` | `1` 与最近浮点数的距离\n",
    "`ndims(a)` | `ndim(a), a.ndim` | `a` 的维数\n",
    "`numel(a)` | `size(a), a.size` | `a` 的元素个数\n",
    "`size(a)` | `shape(a), a.shape` | `a` 的形状\n",
    "`size(a,n)` | `a.shape[n-1]` | 第 n 维的大小\n",
    "`a(2,5)` | `a[1,4]` | 第 2 行第 5 列元素\n",
    "`a(2,:)` | `a[1], a[1,:]` | 第 2 行 \n",
    "`a(1:5,:)` | `a[0:5]` | 第 1 至 5 行\n",
    "`a(end-4:end,:)` | `a[-5:]` | 后 5 行\n",
    "`a(1:3,5:9)` | `a[0:3][:,4:9]` | 特定行列（1~3 行，5~9 列）\n",
    "`a([2,4,5],[1,3])` | `a[ix_([1,3,4],[0,2])]` | 特定行列（2,4,5 行的 1,3 列）\n",
    "`a(3:2:21,:)` | `a[2:21:2,:]` | 特定行列（3,5,...,21 行）\n",
    "`a(1:2:end,:)` | `a[ ::2,:]` | 奇数行\n",
    "`a([1:end 1],:)` | `a[r_[:len(a),0]]` | 将第一行添加到末尾\n",
    "`a.'` | `a.T` | 转置\n",
    "`a ./ b` | `a/b` | 逐元素除法\n",
    "`(a>0.5)` | `(a>0.5)` | 各个元素是否大于 0.5\n",
    "`find(a>0.5)` | `nonzero(a>0.5)` | 大于 0.5 的位置\n",
    "`a(a<0.5)=0` | `a[a<0.5]=0` | 小于 0.5 的设为 0\n",
    "`a(:) = 3` | `a[:] = 3` | 所有元素设为 3\n",
    "`y=x` | `y=x.copy()` | 将 y 设为 x\n",
    "`y=x(2,:)` | `y=x[1,:].copy()` | 注意值传递和引用传递的区别\n",
    "`y=x(:)` | `y=x.flatten(1)` | 将矩阵变为一个向量，这里 `1` 表示沿着列进行转化\n",
    "`max(max(a))` | `a.max()` | 最大值\n",
    "`max(a)` | `a.max(0)` | 每一列的最大值\n",
    "`max(a,[],2)` | `a.max(1)` | 每一行的最大值\n",
    "`max(a,b)` | `maximum(a,b)` | 逐元素比较，取较大的值\n",
    "`a & b` | `logical_and(a, b)` | 逻辑 AND\n",
    "`bitand(a, b)` | `a & b` | 逐比特 AND\n",
    "`inv(a)` | `linalg.inv(a)` | a 的逆\n",
    "`pinv(a)` | `linalg.inv(a)` | 伪逆\n",
    "`rank(a)` | `linalg.matrix_rank(a)` | 秩\n",
    "`a\\b` | `linalg.solve(a,b)(如果a是方阵),linalg.lstsq(a,b)` | 解 `a x = b`\n",
    "`b/a` | 求解 `a.T x.T = b.T` | 解 `x a = b`\n",
    "`[U,S,V]=svd(a)` | `U, S, Vh = linalg.svd(a), V = Vh.T` | 奇异值分解\n",
    "`chol(a)` | `linalg.cholesky(a).T` | Cholesky 分解\n",
    "`[V,D]=eig(a)` | `D,V = linalg.eig(a)` | 特征值分解\n",
    "`[V,D]=eig(a,b)` | `V,D = scipy.linalg.eig(a,b)` | \n",
    "`[V,D]=eigs(a,k)` |  | 前 k 大特征值对应的特征向量\n",
    "`` | `` |\n",
    "`` | `` |\n",
    "`` | `` |\n",
    "`` | `` |\n",
    "\n",
    "MATLAB|numpy.array|numpy.matrix|注释\n",
    "---|---|---|---\n",
    "`[1,2,3;4,5,6]` | `array([[1.,2.,3.],[4.,5.,6.]])` | `mat([[1.,2.,3.],[4.,5.,6.]]), mat('1,2,3;4,5,6')` | `2x3` 矩阵\n",
    "`[a b;c d]` | `vstack([hstack([a,b]), hsatck([c,d])]])` | `bmat('a b;c d')` | 分块矩阵构造\n",
    "`a(end)` | `a[-1]` | `a[:,-1][0,0]` | 最后一个元素\n",
    "`a'` | `a.conj().T` | `a.H` | 复共轭转置\n",
    "`a * b` | `dot(a,b)` | `a * b` | 矩阵乘法\n",
    "`a .* b` | `a * b` | `multiply(a,b)` | 逐元素乘法\n",
    "`a.^3` | `a**3` | `power(a,3)` | 逐元素立方\n",
    "`a(:,find(v>0.5))` | `a[:,nonzero(v>0.5)[0]]` | `a[:,nonzero(v.A>0.5)[0]]` | 找出行向量 `v>0.5` 对应的 `a` 中的列\n",
    "`a(:,find(v>0.5))` | `a[:,v.T>0.5]` | `a[:,v.T>0.5)]` | 找出列向量 `v>0.5` 对应的 `a` 中的列\n",
    "`a .* (a>0.5)` | `a * (a>0.5)` | `mat(a.A * (a>0.5).A)` | 将所有小于 0.5 的元素设为 0\n",
    "`1:10` | `arange(1.,11.), r_[1.:11.], r_[1:10:10j]` | `mat(arange(1.,11.)), r_[1.:11., 'r']` | 这里 `1.` 是为了将其转化为浮点数组\n",
    "`0:9` | `arange(10.), r_[:10.], r_[:9:10j]` | `mat(arange(10.)), r_[:10., 'r']` | \n",
    "`[1:10]'` | `arange(1.,11.)[:,newaxis]` | `r_[1.:11.,'c']` | 列向量\n",
    "`zeros, ones, eye, diag, linspace` | `zeros, ones, eye, diag, linspace` | `mat(...)` |\n",
    "`rand(3,4)` | `random.rand(3,4)` | `mat(...)` | 0~1 随机数\n",
    "`[x,y]=meshgrid(0:8,0:5)` | `mgrid[0:9., 0:6.], meshgrid(r_[0:9.],r_[0:6.])` | `mat(...)` | 网格\n",
    "| `ogrid[0:9.,0:6.], ix_(r_[0:9.],r_[0:6.])` | `mat()` | 建议在 `Numpy` 中使用\n",
    "`[x,y]=meshgrid([1,2,4],[2,4,5])`|`meshgrid([1,2,4],[2,4,5])`|`mat(...)`|\n",
    "|`ix_([1,2,4],[2,4,5])`|`mat(...)`|\n",
    "`repmat(a, m, n)`|`tile(a, (m,n))`|`mat(...)`| 产生 `m x n` 个 `a`\n",
    "`[a b]` | `c_[a,b]`|`concatenate((a,b),1)`| 列对齐连接\n",
    "`[a; b]` | `r_[a,b]`|`concatenate((a,b))`| 行对齐连接\n",
    "`norm(v)` | `sqrt(dot(v,v)), linalg.norm(v)` | `sqrt(dot(v.A,v.A)), linalg.norm(v)` | 模\n",
    "`[Q,R,P]=qr(a,0)` | `Q,R = scipy.linalg.qr(a)` | `mat(...)` | QR 分解\n",
    "`[L,U,P]=lu(a)` | `L,U = Sci.linalg.lu(a)` | `mat(...)` | LU 分解\n",
    "`fft(a)` | `fft(a)` | `mat(...)` | FFT\n",
    "`ifft(a)` | `ifft(a)` | `mat(...)` | IFFT\n",
    "`sort(a)` | `sort(a),a.sort` | `mat(...)` | 排序\n",
    "\n",
    "参考：http://wiki.scipy.org/NumPy_for_Matlab_Users#whichNotes"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
